#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
通知组件模块
支持跨平台的通知显示，在不同操作系统显示在不同位置：
- macOS: 右上角
- Windows/Linux: 右下角
"""

import platform
from pathlib import Path
from typing import Optional
from PySide6.QtWidgets import (
    QWidget, QLabel, QVBoxLayout, QHBoxLayout, 
    QPushButton, QGraphicsDropShadowEffect, QFrame
)
from PySide6.QtCore import (
    Qt, QTimer, QPropertyAnimation, QEasingCurve, 
    QRect, Signal, QParallelAnimationGroup, QMetaObject, QThread
)
from PySide6.QtGui import QFont, QColor, QPixmap, QPainter, QPainterPath


class NotificationWidget(QFrame):
    """通知窗口组件"""
    
    # 信号：通知被点击或关闭
    notification_clicked = Signal()
    notification_closed = Signal()
    
    def __init__(self, 
                 title: str,
                 message: str,
                 duration: int = 5000,
                 notification_type: str = "success",
                 parent: Optional[QWidget] = None):
        super().__init__(parent)
        
        self.title = title
        self.message = message
        self.duration = duration
        self.notification_type = notification_type
        
        # 确定操作系统风格
        self.system_style = "macos" if platform.system().lower() == "darwin" else "windows"
        
        # 设置窗口属性
        self.setWindowFlags(
            Qt.WindowType.FramelessWindowHint | 
            Qt.WindowType.WindowStaysOnTopHint |
            Qt.WindowType.Tool
        )
        
        # 设置透明背景，让自定义绘制的圆角正确显示
        self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
        self.setAttribute(Qt.WidgetAttribute.WA_ShowWithoutActivating)
        
        # 初始化UI
        self._setup_ui()
        self._setup_animations()
        self._setup_timer()
        
        # 设置位置
        self._position_notification()
    
    def _setup_ui(self):
        """设置UI界面"""
        # 设置固定大小
        self.setFixedSize(360, 110)
        
        # 设置通知容器的CSS类
        self.setProperty("class", f"notification {self.system_style}")
        
        # 主布局
        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(20, 16, 20, 16)
        main_layout.setSpacing(8)
        
        # 顶部布局：图标、标题和关闭按钮
        top_layout = QHBoxLayout()
        
        # 图标标签
        self.icon_label = QLabel()
        self.icon_label.setFixedSize(20, 20)
        self.icon_label.setScaledContents(True)
        # 设置图标
        self._set_notification_icon()
        
        # 标题标签
        self.title_label = QLabel(self.title)
        # 设置标题的CSS类
        self.title_label.setProperty("class", f"notification-title {self.system_style} {self.notification_type}")
        
        # 关闭按钮
        self.close_btn = QPushButton("×")
        self.close_btn.setFixedSize(20, 20)
        self.close_btn.clicked.connect(self.close_notification)
        # 设置关闭按钮的CSS类
        self.close_btn.setProperty("class", f"notification-close {self.system_style}")
        
        top_layout.addWidget(self.icon_label)
        top_layout.addSpacing(8)  # 图标和标题之间的间距
        top_layout.addWidget(self.title_label)
        top_layout.addStretch()
        top_layout.addWidget(self.close_btn)
        
        # 消息标签
        self.message_label = QLabel(self.message)
        self.message_label.setWordWrap(True)
        # 设置消息的CSS类
        self.message_label.setProperty("class", f"notification-message {self.system_style}")
        
        main_layout.addLayout(top_layout)
        main_layout.addWidget(self.message_label)
        main_layout.addStretch()
        
        # 添加阴影效果
        self._setup_shadow()
    
    def _set_notification_icon(self):
        """设置通知图标"""
        # 获取图标文件路径
        current_dir = Path(__file__).parent.parent
        icons_dir = current_dir / "resources" / "icons"
        
        # 根据系统风格选择图标文件名后缀
        suffix = "" if self.system_style == "macos" else "-win"
        icon_filename = f"notification-{self.notification_type}{suffix}.svg"
        icon_path = icons_dir / icon_filename
        
        if icon_path.exists():
            pixmap = QPixmap(str(icon_path))
            self.icon_label.setPixmap(pixmap)
        else:
            # 如果图标文件不存在，显示默认文字
            icon_text = {
                "success": "✓",
                "error": "✕", 
                "warning": "⚠",
                "info": "ℹ"
            }.get(self.notification_type, "•")
            self.icon_label.setText(icon_text)
            self.icon_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
            # 设置图标标签的CSS类用于文字图标样式
            self.icon_label.setProperty("class", f"notification-icon-text {self.system_style} {self.notification_type}")
    
    def _setup_shadow(self):
        """设置阴影效果"""
        shadow = QGraphicsDropShadowEffect()
        
        # 根据系统调整阴影效果
        if self.system_style == "macos":  # macOS 风格阴影
            shadow.setBlurRadius(25)
            shadow.setColor(QColor(0, 0, 0, 80))
            shadow.setOffset(0, 8)
        else:  # Windows/Linux 风格阴影
            shadow.setBlurRadius(20)
            shadow.setColor(QColor(0, 0, 0, 120))
            shadow.setOffset(0, 6)
        
        self.setGraphicsEffect(shadow)
    
    def _setup_animations(self):
        """设置动画"""
        # 淡入动画
        self.fade_in_animation = QPropertyAnimation(self, b"windowOpacity")
        self.fade_in_animation.setDuration(400)
        self.fade_in_animation.setStartValue(0.0)
        self.fade_in_animation.setEndValue(1.0)
        self.fade_in_animation.setEasingCurve(QEasingCurve.Type.OutCubic)
        
        # 淡出动画
        self.fade_out_animation = QPropertyAnimation(self, b"windowOpacity")
        self.fade_out_animation.setDuration(300)
        self.fade_out_animation.setStartValue(1.0)
        self.fade_out_animation.setEndValue(0.0)
        self.fade_out_animation.setEasingCurve(QEasingCurve.Type.InCubic)
        self.fade_out_animation.finished.connect(self.deleteLater)
        
        # 滑入动画
        self.slide_in_animation = QPropertyAnimation(self, b"geometry")
        self.slide_in_animation.setDuration(400)
        self.slide_in_animation.setEasingCurve(QEasingCurve.Type.OutCubic)
        
        # 组合动画
        self.show_animation_group = QParallelAnimationGroup()
        self.show_animation_group.addAnimation(self.fade_in_animation)
        self.show_animation_group.addAnimation(self.slide_in_animation)
    
    def _setup_timer(self):
        """设置自动关闭定时器"""
        if self.duration > 0:
            self.auto_close_timer = QTimer()
            self.auto_close_timer.setSingleShot(True)
            self.auto_close_timer.timeout.connect(self.close_notification)
    
    def _position_notification(self):
        """根据操作系统定位通知位置"""
        from PySide6.QtGui import QGuiApplication
        
        # 获取主屏幕
        screen = QGuiApplication.primaryScreen()
        screen_geometry = screen.availableGeometry()
        
        # 通知边距
        margin = 20
        
        # 根据操作系统决定位置
        if self.system_style == "macos":  # macOS - 右上角
            x = screen_geometry.right() - self.width() - margin
            y = screen_geometry.top() + margin
            
            # 设置滑入动画的起始和结束位置（从右侧滑入）
            start_rect = QRect(x + self.width(), y, self.width(), self.height())
            end_rect = QRect(x, y, self.width(), self.height())
            
        else:  # Windows/Linux - 右下角
            x = screen_geometry.right() - self.width() - margin
            y = screen_geometry.bottom() - self.height() - margin
            
            # 设置滑入动画的起始和结束位置（从右侧滑入）
            start_rect = QRect(x + self.width(), y, self.width(), self.height())
            end_rect = QRect(x, y, self.width(), self.height())
        
        # 设置动画
        self.slide_in_animation.setStartValue(start_rect)
        self.slide_in_animation.setEndValue(end_rect)
        
        # 设置初始位置（动画起始位置）
        self.setGeometry(start_rect)
    
    def show_notification(self):
        """显示通知"""
        self.show()
        self.show_animation_group.start()
        
        # 启动自动关闭定时器
        if hasattr(self, 'auto_close_timer'):
            self.auto_close_timer.start(self.duration)
    
    def close_notification(self):
        """关闭通知"""
        # 停止自动关闭定时器
        if hasattr(self, 'auto_close_timer'):
            self.auto_close_timer.stop()
        
        # 发射关闭信号
        self.notification_closed.emit()
        
        # 开始淡出动画
        self.fade_out_animation.start()
    
    def mousePressEvent(self, event):
        """鼠标点击事件"""
        if event.button() == Qt.MouseButton.LeftButton:
            self.notification_clicked.emit()
            self.close_notification()
        super().mousePressEvent(event)

    def paintEvent(self, event):
        """自定义绘制事件 - 绘制圆角背景"""
        painter = QPainter(self)
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)
        
        # 创建圆角矩形路径
        path = QPainterPath()
        rect = self.rect()
        border_radius = 12  # 12px圆角
        path.addRoundedRect(rect, border_radius, border_radius)
        
        # 根据系统风格设置不同的背景色和边框
        if self.system_style == "macos":
            # macOS风格：白色背景，浅灰色边框
            painter.fillPath(path, QColor(255, 255, 255, 250))  # 略微透明的白色
            painter.setPen(QColor(224, 224, 224))  # 浅灰色边框
        else:
            # Windows/Linux风格：深色半透明背景
            if self.notification_type == "success":
                painter.fillPath(path, QColor(76, 175, 80, 230))  # 绿色
            elif self.notification_type == "error":
                painter.fillPath(path, QColor(244, 67, 54, 230))  # 红色
            elif self.notification_type == "warning":
                painter.fillPath(path, QColor(255, 152, 0, 230))  # 橙色
            else:  # info
                painter.fillPath(path, QColor(33, 150, 243, 230))  # 蓝色
            painter.setPen(QColor(255, 255, 255, 100))  # 半透明白色边框
            
        painter.drawPath(path)
        
        super().paintEvent(event)


class NotificationManager:
    """通知管理器"""
    
    _instance = None
    _notifications = []
    _style_loaded = False
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    @classmethod
    def _load_styles(cls):
        """加载样式文件"""
        if cls._style_loaded:
            return
            
        from PySide6.QtWidgets import QApplication
        app = QApplication.instance()
        if app is None:
            return
            
        # 获取样式文件路径
        current_dir = Path(__file__).parent.parent
        style_file = current_dir / "resources" / "styles" / "modern_light.qss"
        
        if style_file.exists():
            try:
                with open(style_file, 'r', encoding='utf-8') as f:
                    style_content = f.read()
                app.setStyleSheet(style_content)
                cls._style_loaded = True
                print(f"已加载样式文件: {style_file}")
            except Exception as e:
                print(f"加载样式文件失败: {e}")
        else:
            print(f"样式文件不存在: {style_file}")
    
    @classmethod
    def show_success(cls, title: str, message: str, duration: int = 5000):
        """显示成功通知"""
        cls._show_notification(title, message, duration, "success")
    
    @classmethod
    def show_error(cls, title: str, message: str, duration: int = 5000):
        """显示错误通知"""
        cls._show_notification(title, message, duration, "error")
    
    @classmethod
    def show_warning(cls, title: str, message: str, duration: int = 5000):
        """显示警告通知"""
        cls._show_notification(title, message, duration, "warning")
    
    @classmethod
    def show_info(cls, title: str, message: str, duration: int = 5000):
        """显示信息通知"""
        cls._show_notification(title, message, duration, "info")
    
    @classmethod
    def show_export_success(cls, file_path: str = "", record_count: int = 0):
        """显示数据导出成功通知"""
        if record_count > 0:
            message = f"成功导出 {record_count:,} 条记录"
            if file_path:
                import os
                message += f"\n文件位置: {os.path.basename(file_path)}"
        else:
            message = "数据导出完成"
            if file_path:
                import os
                message += f"\n文件位置: {os.path.basename(file_path)}"
        
        cls.show_success("导出成功", message, duration=6000)
    
    @classmethod
    def _show_notification(cls, title: str, message: str, duration: int, notification_type: str):
        """内部方法：显示通知"""
        from PySide6.QtWidgets import QApplication
        
        # 检查是否在主线程中
        app = QApplication.instance()
        if app is None:
            print("警告：没有QApplication实例，无法显示通知")
            return
        
        if QThread.currentThread() != app.thread():
            # 不在主线程中，使用QTimer.singleShot在主线程中执行
            QTimer.singleShot(0, lambda: cls._create_and_show_notification(title, message, duration, notification_type))
        else:
            # 在主线程中，直接执行
            cls._create_and_show_notification(title, message, duration, notification_type)
    
    @classmethod
    def _create_and_show_notification(cls, title: str, message: str, duration: int, notification_type: str):
        """创建并显示通知（必须在主线程中调用）"""
        # 加载样式文件
        cls._load_styles()
        
        # 清理已关闭的通知
        cls._notifications = [n for n in cls._notifications if n and not n.isHidden()]
        
        # 如果已有通知，调整新通知的位置
        if cls._notifications:
            cls._adjust_notification_positions()
        
        # 创建新通知
        notification = NotificationWidget(
            title=title,
            message=message,
            duration=duration,
            notification_type=notification_type
        )
        
        # 连接关闭信号，用于清理
        notification.notification_closed.connect(lambda: cls._remove_notification(notification))
        
        # 添加到列表并显示
        cls._notifications.append(notification)
        notification.show_notification()
    
    @classmethod
    def _adjust_notification_positions(cls):
        """调整现有通知的位置，为新通知腾出空间"""
        system_style = "macos" if platform.system().lower() == "darwin" else "windows"
        notification_height = 110 + 15  # 通知高度 + 间距
        
        for i, notification in enumerate(cls._notifications):
            if notification and not notification.isHidden():
                current_rect = notification.geometry()
                
                if system_style == "macos":  # macOS - 向下移动
                    new_y = current_rect.y() + notification_height
                else:  # Windows/Linux - 向上移动
                    new_y = current_rect.y() - notification_height
                
                new_rect = QRect(current_rect.x(), new_y, current_rect.width(), current_rect.height())
                
                # 使用动画移动现有通知
                move_animation = QPropertyAnimation(notification, b"geometry")
                move_animation.setDuration(300)
                move_animation.setStartValue(current_rect)
                move_animation.setEndValue(new_rect)
                move_animation.setEasingCurve(QEasingCurve.Type.OutCubic)
                move_animation.start()
    
    @classmethod
    def _remove_notification(cls, notification):
        """移除通知"""
        if notification in cls._notifications:
            cls._notifications.remove(notification)


# 便捷函数
def show_success_notification(title: str, message: str, duration: int = 5000):
    """显示成功通知的便捷函数"""
    NotificationManager.show_success(title, message, duration)


def show_error_notification(title: str, message: str, duration: int = 5000):
    """显示错误通知的便捷函数"""
    NotificationManager.show_error(title, message, duration)


def show_warning_notification(title: str, message: str, duration: int = 5000):
    """显示警告通知的便捷函数"""
    NotificationManager.show_warning(title, message, duration)


def show_info_notification(title: str, message: str, duration: int = 5000):
    """显示信息通知的便捷函数"""
    NotificationManager.show_info(title, message, duration)


def show_export_success_notification(file_path: str = "", record_count: int = 0):
    """显示数据导出成功通知的便捷函数"""
    NotificationManager.show_export_success(file_path, record_count) 